package cn.asiontang.xposed.url_firewall;

import android.text.TextUtils;

import cn.asiontang.xposed.LogEx;
import cn.asiontang.xposed.XposedUtils;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.callbacks.XC_LoadPackage;

public class XposedHookClass_String
{
    private static final String TAG = XposedHookClass_String.class.getName();

    /**
     * <pre>
     * 此方法优点:
     *      1.能同时捕获 所有字符串里的网址
     * 此方法缺点:
     *      1.捕获 记录大量日志,增加日志尺寸
     *      2.减慢运行速度
     * </pre>
     * <p><b>测试用例如下:</b></p>
     * <pre>
     * </pre>
     */
    public static void hook(final XC_LoadPackage.LoadPackageParam loadPackageParam)
    {
        try
        {
            final boolean enableHookStringWithContains = Config.get4hook().isEnableHookStringWithContains();
            final boolean enableHookStringWithLength = Config.get4hook().isEnableHookStringWithLength();
            if (!enableHookStringWithContains && !enableHookStringWithLength)
            {
                LogEx.log(TAG, "HookString:Faild: enableHookStringWithContains=false && enableHookStringWithLength=false");
                return;
            }

            final String hookStringContainsText = Config.get4hook().getHookStringContainsText();
            if (enableHookStringWithContains)
            {
                if (TextUtils.isEmpty(hookStringContainsText))
                {
                    LogEx.log(TAG, "HookString:Faild; Need No Empty ! getHookStringContainsText=" + hookStringContainsText);
                    return;
                }
                else
                    LogEx.log(TAG, "HookString:OK; getHookStringContainsText=" + hookStringContainsText);
            }

            final String hookStringLength = Config.get4hook().getHookStringLength();
            if (enableHookStringWithLength)
            {
                if (TextUtils.isEmpty(hookStringLength)
                        || "=0".equalsIgnoreCase(hookStringLength)
                        || "0".equalsIgnoreCase(hookStringLength))
                {
                    LogEx.log(TAG, "HookString:Faild; Need No -1 ! getHookStringLength=" + hookStringLength);
                    return;
                }
                else
                    LogEx.log(TAG, "HookString:OK; getHookStringLength=" + hookStringLength);
            }

            final String hookStringAndReplaceBefore = Config.get4hook().getHookStringAndReplaceBefore();
            final String hookStringAndReplaceAfter = Config.get4hook().getHookStringAndReplaceAfter();
            final boolean enableHookStringAndReplace = Config.get4hook().isEnableHookStringAndReplace()
                    && !TextUtils.isEmpty(hookStringAndReplaceBefore)
                    && !TextUtils.isEmpty(hookStringAndReplaceAfter);
            LogEx.log(TAG, "HookString:OK; enableHookStringAndReplace=" + enableHookStringAndReplace
                    + " Before=" + hookStringAndReplaceBefore
                    + " After=" + hookStringAndReplaceAfter);

            //><=
            final boolean isHadGreaterThan = hookStringLength.contains(">");
            final boolean isHadLessThan = hookStringLength.contains("<");
            final boolean isHadEqualTo = hookStringLength.contains("=");
            final int iHookStringLength = Integer.parseInt(hookStringLength.replace(">", "").replace("<", "").replace("=", ""));

            //获取具体请求的网址
            XposedUtils.realHookAllConstructors("java.lang.String", loadPackageParam.classLoader, new XC_MethodHook()
            {
                String lastMatch = null;

                @Override
                protected void afterHookedMethod(final MethodHookParam param) throws Throwable
                {
                    String string = (String) param.thisObject;

                    boolean isOK = true;
                    if (enableHookStringWithContains && !string.contains(hookStringContainsText))
                        isOK = false;
                    if (enableHookStringWithLength && !isMatch(string.length()))
                        isOK = false;

                    if (!isOK)
                    {
                        if (BuildConfig.DEBUG)
                            LogEx.log(TAG, "不匹配的字符串:", string, "String.length", string.length());
                        return;
                    }

                    //存在一个字符串多次被实例化的情况,所以不必要连续重复输出.
                    if (lastMatch != null && lastMatch.equalsIgnoreCase(string))
                        return;
                    lastMatch = string;

                    LogEx.log(TAG, "成功捕获可能包含网址的字符串:", "String.length", string.length());
                    LogEx.log(TAG, "成功捕获可能包含网址的字符串:", "String", string);

                    if (enableHookStringAndReplace)
                    {
                        String replaceResult = string.replaceAll(hookStringAndReplaceBefore, hookStringAndReplaceAfter);
                        if (replaceResult.equalsIgnoreCase(string))
                        {
                            //LogEx.log(TAG,"string.replaceAll 替换失败! 替换后和替换前字符串完全一样!");

                            replaceResult = string.replace(hookStringAndReplaceBefore, hookStringAndReplaceAfter);
                            if (replaceResult.equalsIgnoreCase(string))
                            {
                                //LogEx.log(TAG,"string.replace 替换失败! 替换后和替换前字符串完全一样!");
                            }
                            else
                            {
                                LogEx.log(TAG, "string.replace 替换成功:", replaceResult);
                                param.setResult(replaceResult);
                            }
                        }
                        else
                        {
                            LogEx.log(TAG, "string.replaceAll 替换成功:", replaceResult);
                            param.setResult(replaceResult);
                        }
                    }
                }

                /**
                 * 5>=1
                 * 1>=1
                 * 2=2
                 * 3<4
                 */
                private boolean isMatch(final int length)
                {
                    if (isHadEqualTo && length == iHookStringLength)
                        return true;
                    if (isHadGreaterThan && length > iHookStringLength)
                        return true;
                    if (isHadLessThan && length < iHookStringLength)
                        return true;
                    return false;
                }
            });
        }
        catch (Exception e)
        {
            LogEx.log(TAG, "hook Exception", e);
        }
    }
}
